/* Zatok - язык программирования текстовых игр
 * (С) 2010 - 2012 Меркулов Матвей Юрьевич
 * Код лицензирован под лицензией GNU LGPL
 * Вы можете прочитать текст лицензии по адресу:
 * http://www.gnu.org/copyleft/lesser.html
 * или прочитать русский перевод по адресу:
 * http://ru.wikisource.org/wiki/GNU_Lesser_General_Public_License
 */

package base.array;

import base.function.CFunction;
import base.value.CArrayValue;
import base.value.CStringValue;
import base.value.CValue;
import base.value.CValue.CType;
import java.util.Arrays;

public class CExtract extends CFunction {
	public CStringValue ReturnedStringValue = new CStringValue( "" );
	public CArrayValue ReturnedArrayValue = new CArrayValue();
	
	
	
	@Override
	public void Init() {
		AssertParam( 3 );
	}
	
	
	
	@Override
	public CValue GetValue() {
		CValue Value = Param[ 0 ].GetValue();
		int Index = Param[ 1 ].ToInt() - 1;
		if ( Value.GetType() == CType.String ) {
			ReturnedStringValue.Value = ToString( Value );
			return ReturnedStringValue;
		} else if ( Value.GetType() == CType.Array ) {
			ReturnedArrayValue.Values = ToArray( Value );
			return ReturnedArrayValue;
		} else {
			Error( "Параметр должен быть строкой или массивом" );
			return null;
		}
	}

	
	
	@Override
	public boolean ToBoolean() {
		CValue Value = Param[ 0 ].GetValue();
		if( Value.GetType() == CType.Array ) {
			return !ToString( Value ).isEmpty();
		} else {
			Error( "Параметр должен быть строкой для получения логического значения" );
			return false;
		}
	}

	
	
	@Override
	public int ToInt() {
		CValue Value = Param[ 0 ].GetValue();
		if ( Value.GetType() == CType.String ) {
			return Integer.parseInt( ToString( Value ) );
		} else {
			Error( "Параметр должен быть строкой для получения целого числа" );
			return 0;
		}
	}

	
	
	@Override
	public float ToFloat() {
		CValue Value = Param[ 0 ].GetValue();
		if ( Value.GetType() == CType.String ) {
			return Float.parseFloat( ToString( Value ) );
		} else {
			Error( "Параметр должен быть строкой  для получения дробного числа" );
			return 0;
		}
	}
	
	
	
	@Override
	public String ToString(){
		CValue Value = Param[ 0 ].GetValue();
		if( Value.GetType() == CType.String ) {
			return ToString( Value );
		} else {
			Error( "Параметр должен быть строкой для получения подстроки" );
			return null;
		}
	}
	
	
	
	@Override
	public CValue[] ToArray() {
		CValue Value = Param[ 0 ].GetValue();
		if( Value.GetType() == CType.Array ) {
			return ToArray( Value );
		} else {
			Error( "Параметр должен быть массивом для получения среза массива" );
			return null;
		}
	}
	
	
	
	public String ToString( CValue Value ){
		String Line = Value.ToString();
		int Length = Line.length();
		
		int Begin = GetBegin( Length, CType.String );
		int End = GetEnd( Begin, Length, CType.String );
		
		return Line.substring( Begin - 1, End );
	}
	


	private CValue[] ToArray( CValue Value ){
		CValue[] Array = Value.ToArray();
		int Length = Array.length;
		
		int Begin = GetBegin( Length, CType.Array );
		int End = GetEnd( Begin, Length, CType.Array );
		
		return Arrays.copyOfRange( Array, Begin - 1, End );
	}
	
	
	
	private int GetBegin( int Length, CType Type ) {
		if( Type != CType.String && Type != CType.Array ) Error( "Параметр должен быть строкой или массивом" );
		int Begin = Param[ 1 ].ToInt();
		if ( Begin < 0 ) Begin = Length + Begin;
		if ( Begin < 1 ) Error( "Номер " + ValueName( false, Type ) + " должен быть больше 0" );
		if ( Begin > Length ) Error( "Номер " + ValueName( false, Type ) + " строки должен быть меньше длины строки" );
		return Begin;
	}
	
	
	
	private int GetEnd( int Begin, int Length, CType Type ) {
		int End = Param[ 2 ].ToInt();
		if ( End < 1 ) End = Length - End;
		if ( End < 1 ) Error( "Номер " + ValueName( true, Type ) + " должен быть больше 0" );
		if ( End > Length ) Error( "Номер " + ValueName( true, Type ) + " должен быть меньше длины строки" );
		if ( Begin > End ) Error( "Номер " + ValueName( false, Type ) + " не может быть больше номера " + ValueName( true, Type ) );
		return End;
	}
	
	
	
	private String ValueName( boolean Ending, CType Type ) {
		String Word = "";
		if( Ending ) Word = "конечного"; else Word = "начального";
		if( Type == CType.String ) {
			return Word + " символа вычленяемой строки";
		} else {
			return Word + " элемента вычленяемого массива";
		}
	}
}
